		TITLE	DIRECTOR - Copyright (C) SLR Systems 1994

		INCLUDE	MACROS
if	V5
		INCLUDE	SEGMSYMS
		INCLUDE	IO_STRUC
		INCLUDE	SYMBOLS

		PUBLIC	BUILD_DIRECTORY,WRITE_DIRECTORY


		.DATA

		EXTERNDEF	OPEN_SPACE:BYTE,SYMBEG:BYTE,TEMP_RECORD:BYTE

		EXTERNDEF	IMP_DEVICE:DWORD,ENTRY:DWORD,NUM_DIR_BLOCKS:DWORD,DELTA_START:DWORD,START_BLOCK:DWORD
		EXTERNDEF	DIR_BLOCKS:DWORD,WONT:DWORD,SYMBOL_LENGTH:DWORD,IMPLIB_PAGESIZE:DWORD,ENTRYNAMES_TOTAL_LENGTH:DWORD
		EXTERNDEF	FINAL_HIGH_WATER:DWORD,ENTRYNAME_COUNT:DWORD,FIRST_ENTRYNAME_GINDEX:DWORD

		EXTERNDEF	ENTRYNAME_GARRAY:STD_PTR_S

		EXTERNDEF	IMP_OUTALL:DWORD


		.CODE	PASS2_TEXT

		EXTERNDEF	ERR_RET:PROC,ERR_ABORT:PROC,CURRENT_OUT_LOCATION:PROC,RELEASE_SEGMENT:PROC,_flush_trunc:proc
		EXTERNDEF	_flush_close:proc,_dosposition_a:PROC,GET_NEW_LOG_BLK:PROC,MOVE_DSSIAX_TO_NEWOMF:PROC

		EXTERNDEF	MAX_DIRS_ERR:ABS,DIR_TOO_BIG:ABS,ERR_NEVER_FIT:ABS


MAX_DIRECTORIES	EQU	2039


MAXED_OUT:
		MOV	AX,DIR_TOO_BIG
		CALL	ERR_ABORT


BUILD_DIRECTORY	PROC
		;
		;THIS IS THE BIG SUBROUTINE,  THIS PUTS EACH SYMBOL INTO THE DIRECTORY
		;AND RETRIES IT WITH A LARGER BLOCK NUMBER UNTIL THE APPROPRIATE NUMBER
		;OF COLLISIONS ARE ENCOUNTERED
		;
		MOV	EAX,ENTRYNAME_COUNT
		XOR	EDX,EDX			;CALCULATE THE LEAST NUMBER OF

		MOV	ECX,36			;BLOCKS THE DIRECTORY NEEDS

		DIV	ECX			;37 ENTRIES MAX PER DIR BLOCK

		MOV	ECX,EAX			;THAT IS THE 37/BLOCK LIMIT
		;
		;NOW, GET TEXT_LIMIT #
		;
		MOV	EAX,ENTRYNAMES_TOTAL_LENGTH
		XOR	EDX,EDX

		MOV	EBX,512-48		;ASSUME AVERAGE 10 BYTES LEFT PER BLOCK

		DIV	EBX			;THAT IS TEXT-SIZE LIMIT

		CMP	EAX,ECX
		JNC	START_LOOP

		MOV	EAX,ECX
START_LOOP:
START_OVER:
		INC	EAX			;INC TO GET NEXT HIGHEST PRIME
		CALL	GET_PRIME

		CMP	EAX,MAX_DIRECTORIES	;TOO MANY
		JA	MAXED_OUT

		MOV	NUM_DIR_BLOCKS,EAX	;OK GOT THE AMOUNT OF BLOCKS
		CALL	CLEAR_DIRECTORY_BUF	;ZERO OUT DIRECTORY POINTERS

		CALL	TBLINIT
		JMP	NS_1

NEXT_SYMBOL1:
		CALL	PUT_SYMBOL_IN_DIRECTORY	;ADD SYMBOL TO DIRECTORY
		JC	START_OVER		;TOO MANY COLLISIONS
NS_1:
		CALL	TBLNEXT			;PTR TO NEXT SYMBOL
		JNZ	NEXT_SYMBOL1
NS_DONE:
		RET

BUILD_DIRECTORY	ENDP


GET_PRIME	PROC	NEAR
		;
		;RETURNS THE CLOSEST PRIME NUMBER GREATER THAN EAX
		;RESULT IN EAX
		;
		
		MOV	EDX,OFF PRIME_NUMBERS
		MOV	ECX,EAX

		XOR	EAX,EAX
GP_LOOP:
		MOV	AX,[EDX]
		ADD	EDX,2

		CMP	EAX,ECX
		JB	GP_LOOP
GP_DONE:
		RET

GET_PRIME	ENDP


CLEAR_DIRECTORY_BUF	PROC	NEAR
		;
		;CLEAR OUT DIRECTORY BUFFER
		;
		;OPEN_SPACE IS A TABLE OF BYTES THAT INDICATE THE NUMBER OF
		;WORDS USED IN EACH DIRECTORY BLOCK
		;
		PUSHM	EDI,ESI,EBX
		MOV	ECX,NUM_DIR_BLOCKS

		MOV	EBX,ECX		;SAVE COPY
		LEA	EDI,OPEN_SPACE

		SHR	ECX,2		;OF EACH BLOCK USED UP BY POINTERS TO
		MOV	EAX,13131313H	;INITIALLY, 13H OR 19 WORDS, 38 BYTES

		INC	ECX		;SYMBOL ENTRIES

		REP	STOSD
		;
		;EBX IS # OF DIRECTORY BLOCKS..
		;
		LEA	ESI,DIRECTORY_BLOCKS
		MOV	EAX,EBX

		MOV	CL,PAGE_SIZE/512	;32

		DIV	CL			;AL IS NUMBER OF FULL 16K BLOCKS

		MOV	BL,AH

		XOR	BH,BH
		AND	EAX,0FFH

		MOV	ECX,EAX
		TEST	EAX,EAX

		JZ	REMAINDER

		PUSH	EBX
CDB_1:
		PUSH	ECX
		MOV	EBX,PAGE_SIZE/512	;32

		CALL	CDB_SUB

		POP	ECX

		DEC	ECX
		JNZ	CDB_1

		POP	EBX

		OR	EBX,EBX
		JZ	CDB_DONE
REMAINDER:
		CALL	CDB_SUB
CDB_DONE:
		POPM	EBX,ESI,EDI

		RET

CDB_SUB:
		;
		;EBX IS # OF 512-BYTE BLOCKS IN THIS BLOCK
		;
		MOV	EDI,[ESI]	;THIS SEGMENT ALLOCATED?
		ADD	ESI,4

		TEST	EDI,EDI
		JZ	CDB_GET_SEG
CDB_SUB_1:
		XOR	EAX,EAX		;NEED TO ZERO OUT 37 BYTES OF POINTERS
					;IN THE FIRST 37 BYTES OF EACH BLOCK
FAST:
		MOV	ECX,80H

		REP	STOSD
;		LEA	DI,512-26H[DI]

		DEC	EBX
		JNZ	FAST

		RET

CDB_GET_SEG:
		;
		;ALLOCATE A 16K BLOCK
		;
		CALL	GET_NEW_LOG_BLK

		MOV	EDI,EAX
		MOV	[ESI-4],EAX

		JMP	CDB_SUB_1

CLEAR_DIRECTORY_BUF	ENDP

PSID_1:
		INC	EDX
		JMP	PSID_2


PUT_SYMBOL_IN_DIRECTORY	PROC	NEAR
		;
		;INSERTS A SYMBOL IN THE DIRECTORY
		;RETURNS A CARRY IF DIRECTORY NEEDS TO BE REBUILT
		;
		;ESI IS SYMBOL
		;ECX IS TEXT
		;
		MOV	EAX,[ESI]._ENT_START_BLOCK	;CALC STARTING BLOCK #
		XOR	EDX,EDX

		DIV	WPTR NUM_DIR_BLOCKS

		MOV	START_BLOCK,EDX		;DIR BLOCK SYMBOL SHOULD BE IN
		MOV	EAX,[ESI]._ENT_DELTA_BLOCK	;

		XOR	EDX,EDX
		PUSH	ECX

		DIV	WPTR NUM_DIR_BLOCKS

		TEST	EDX,EDX
		JZ	PSID_1		;DELTA MUST BE AT LEAST 1
PSID_2::
		MOV	DELTA_START,EDX	;DELTA IF CAN'T FIX IN FIRST BLOCK
		MOV	AL,[ESI]._ENT_START_ENTRY

		MOV	BPTR ENTRY,AL	;ENTRY POINT WITHIN BLOCK
		MOV	AL,[ESI]._ENT_DELTA_ENTRY

		MOV	DELTA_ENTRY,AL	;IF CAN'T STORE AT FIRST ENTRY POINT
		MOV	EAX,NUM_DIR_BLOCKS

		MOV	EDX,START_BLOCK
		MOV	WONT,EAX
BLOCK_LOOP:
		;
		;EDX IS BLOCK #, CONVERT TO PAGE_SIZE BLOCK IN BX, OFFSET IN DI
		;
		MOV	EBX,EDX
		MOV	EDI,EDX

		SHR	EBX,PAGE_BITS-9
		AND	EDI,PAGE_MASK SHR 9

		SHL	EDI,9
		MOV	EAX,DIRECTORY_BLOCKS[EBX*4]

		MOV	EBX,ENTRY
		ADD	EDI,EAX

		MOV	ECX,37		;37 ENTRIES TO CHECK
		MOV	AH,DELTA_ENTRY
ENTRY_LOOP:
		MOV	AL,[EDI+EBX]
		ADD	BL,AH

		OR	AL,AL		;IS THIS ENTRY OPEN ?
		JZ	ENTRY_AVAILABLE

		CMP	BL,37
		JC	L1$		;EQUAL CHANCE OF HAPPENING
		SUB	BL,37
L1$:
		DEC	ECX
		JNZ	ENTRY_LOOP
DO_DELTA_BLOCK:
		MOV	EAX,DELTA_START
		MOV	ENTRY,EBX	;CONTINUE ENTRY FROM HERE...

		ADD	EDX,EAX
		MOV	EAX,NUM_DIR_BLOCKS

		CMP	EDX,EAX
		JC	L2$
		SUB	EDX,EAX
L2$:
		DEC	WONT
		JNZ	BLOCK_LOOP
FAIL:
		JMP	RE_BUILD	;BIG FAILURE...

ENTRY_AVAILABLE:
		;
		;SI PTR SYMBOL LENGTH
		;ES:DI IS PTR THIS BLOCK
		;DX IS BLOCK # * 256
		;CX IS
		;BX IS ENTRY #
		;AX IS
		;
		SUB	BL,AH
		MOV	EAX,SYMBOL_LENGTH

		PUSH	EBX		;SAVE ENTRY #
		MOV	EBX,EDX

		OR	AH,AH
		JZ	L3$

		ADD	EAX,LONG_OMF_DELTA	;ROOM FOR FF, 00
L3$:
		SHR	EAX,1		;# OF WORDS
		MOV	CL,OPEN_SPACE[EBX]

		ADD	AL,4/2		;OVERHEAD(LENGTH, 2-BYTE PTR, ROUND)

		ADD	AL,CL
		JC	FILLED_BLOCK	;OVERFLOW, CANNOT FIT...

		MOV	OPEN_SPACE[EBX],AL
		POP	EDX		;RESTORE ENTRY #

		MOV	EBX,[ESI]._ENT_LIBRARY_PAGE
		MOV	EAX,SYMBOL_LENGTH

		MOV	[EDI+EDX],CL	;STORE DESTINATION ADDRESS...
		LEA	EDI,[EDI+ECX*2]	;ACTUAL POSITION WITHIN BLOCK
		;
		;NOW, MOVE SYMBOL THERE
		;
		POP	ESI
		CALL	MOVE_DSSIAX_TO_NEWOMF

		MOV	WPTR [EDI],BX	;STORE PAGE #
		ADD	EDI,3

		AND	EDI,0FFFFFFFEH

		RET

FILLED_BLOCK:
		;
		;DIRECTORY BLOCK IS FILLED MARK IT SO
		;
		MOV	AL,-1

		MOV	OPEN_SPACE[EBX],AL
		POP	EBX			;ENTRY #

		MOV	BPTR 37[EDI],AL		;MARK OVERFLOW
		JMP	DO_DELTA_BLOCK

RE_BUILD:
		;
		;RETURN WITH THE CARRY SET, SO THE DIRECTORY WILL BE REBUILT
		;WITH MORE BLOCKS ALLOCATED
		;
		CMP	ESP,-1
		MOV	EAX,NUM_DIR_BLOCKS

		POP	ECX

		RET

PUT_SYMBOL_IN_DIRECTORY	ENDP


WRITE_DIRECTORY	PROC
		;
		;SAVE THE DIRECTORY TO DISK, AND GET THE OFFSET OF IT
		;
		;SET OUTPUT FILE TO 512-BYTE BOUNDARY
		;
		MOV	EBX,IMP_DEVICE
		MOV	EDI,OFF TEMP_RECORD
		ASSUME	EBX:PTR MYO_STRUCT

		XOR	ECX,ECX
		MOV	EDX,[EBX].MYO_BYTE_OFFSET

		SUB	ECX,EDX

		AND	ECX,512-1
		JNZ	L2$

		MOV	ECX,512
L2$:
		MOV	EBX,ECX
		SUB	ECX,3

		SHL	ECX,8
		XOR	EAX,EAX

		MOV	CL,0F1H

		MOV	[EDI],ECX
		ADD	EDI,4

		SHR	ECX,10

		REP	STOSD

		MOV	EAX,OFF TEMP_RECORD
		MOV	ECX,EBX

		CALL	IMP_OUTALL
		;
		;NOW DEFINE LIB_HEADER
		;
		MOV	EBX,IMP_DEVICE
		MOV	EAX,NUM_DIR_BLOCKS
		ASSUME	EBX:PTR MYO_STRUCT

		MOV	ECX,[EBX].MYO_BYTE_OFFSET
		MOV	DIR_BLOCKS,EAX

		SHL	EAX,9
		MOV	DIR_LOCATION,ECX
		;
		;WRITE 16K AT A TIME TILL HIGH_WATER...
		;
		PUSH	EAX		;LEFT-OVER BYTES...
		MOV	ECX,EAX

		SHR	ECX,PAGE_BITS
		;
		;CX IS # OF 16K BLOCKS TO WRITE
		;
		LEA	EBX,DIRECTORY_BLOCKS
		ASSUME	EBX:NOTHING

		JZ	CV_MAIN_DONE
L1$:
		PUSH	ECX
		MOV	ECX,PAGE_SIZE

		CALL	WRITE_BLOCK

		POP	ECX
		ADD	EBX,4

		DEC	ECX
		JNZ	L1$
CV_MAIN_DONE:
		POP	ECX

		AND	ECX,PAGE_SIZE-1
		JZ	L9$

		CALL	WRITE_BLOCK
L9$:
		;
		;FLUSH AND CLOSE .LIB FILE
		;
		MOV	EAX,IMP_DEVICE
		push	EAX
		CALL	_flush_trunc		;TRUNCATE, DON'T CLOSE YET
		add	ESP,4

		XOR	ECX,ECX
		MOV	EAX,IMP_DEVICE

		push	ECX
		push	EAX
		call	_dosposition_a
		add	ESP,8

		MOV	EBX,IMPLIB_PAGESIZE
		LEA	EAX,LIB_HEADER

		SUB	EBX,3
		MOV	ECX,16

		MOV	[EAX+1],BX
		CALL	IMP_OUTALL		;RE-WRITE FIRST 16 BYTES

		MOV	EAX,IMP_DEVICE
		push	EAX
		call	_flush_close		;NOW CLOSE
		add	ESP,4
		ret

WRITE_DIRECTORY	ENDP


WRITE_BLOCK	PROC	NEAR
		;
		;
		;
		XOR	EDX,EDX
		MOV	EAX,[EBX]

		MOV	[EBX],EDX
		PUSH	EAX

		CALL	IMP_OUTALL

		POP	EAX
		JMP	RELEASE_SEGMENT

WRITE_BLOCK	ENDP


TBLINIT		PROC	PRIVATE
		;
		;SET UP FOR GETTING SYMBOLS FROM TABLE
		;

		MOV	EAX,FIRST_ENTRYNAME_GINDEX

		MOV	TBL_NEXT,EAX

		RET

TBLINIT		ENDP


TBLNEXT		PROC	PRIVATE
		;
		;RETURNS ESI IS ENT_STRUCT
		;	 ECX IS _TEXT PTR
		;
		MOV	ESI,TBL_NEXT
		XOR	EDX,EDX
L1$:
		TEST	ESI,ESI
		JZ	L9$

		CONVERT	ESI,ESI,ENTRYNAME_GARRAY
		ASSUME	ESI:PTR ENT_STRUCT

		MOV	ECX,ESI
		MOV	AL,[ESI]._ENT_FLAGS

		MOV	ESI,[ESI]._ENT_NEXT_ENT_GINDEX
		TEST	AL,MASK ENT_PRIVATE+MASK ENT_UNDEFINED

		MOV	TBL_NEXT,ESI
		JNZ	L1$

		ASSUME	ECX:PTR ENT_STRUCT
		MOV	ESI,ECX
		TEST	AL,MASK ENT_USE_EXTNAM

		LEA	ECX,[ECX]._ENT_TEXT
		JNZ	L3$
		ASSUME	ECX:NOTHING

		MOV	ECX,[ESI]._ENT_INTERNAL_NAME_GINDEX

		CONVERT	ECX,ECX,SYMBOL_GARRAY
		ASSUME	ECX:PTR SYMBOL_STRUCT

		ADD	ECX,SYMBOL_STRUCT._S_NAME_TEXT
		ASSUME	ECX:NOTHING
L3$:
		MOV	AL,[ECX+EDX]
		INC	EDX

		OR	AL,AL
		JNZ	L3$

		DEC	EDX

		MOV	SYMBOL_LENGTH,EDX
		OR	AL,-1
L9$:
		RET

TBLNEXT		ENDP


		.CONST

		ALIGN	4

PRIME_NUMBERS	DW	1,2,3,5,7,11,13,17,19,23,29,31,37,41,47				;DELTA AT LEAST 10%...	43
		DW	53,59,67,73,83,97,107,113			;61, 71, 79, 89, 101, 103, 109
		DW	113,127

		DW	0089H,0095H,009DH,00A7H,00B3H			;DELTA 6.25 %
		DW	00BFH,00C7H,00D3H,00DFH,00EFH
		DW	0101H,010FH,011BH,0125H
		DW	0137H,014BH,0161H,0175H
		DW	018DH,01A5H
		DW	01C1H,01DFH
		DW	01FDH,021DH,023BH
		DW	025FH,0283H
		DW	02ABH,02D7H
		DW	0305H
		DW	0335H,036DH
		DW	03A1H
		DW	03D1H,03FDH
		DW	1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117
 		DW	1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237
 		DW	1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381
 		DW	1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499
 		DW	1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619
 		DW	1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759
		DW	1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907
 		DW	1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039
		DW	0ffffH


.DATA

LIB_HEADER	DB	0F0H,16-3,0

DIR_LOCATION	DD	0
DIR_BLOCKS	DD	0
		DB	5 DUP(0)


.DATA?

TBL_NEXT	DD	?
DELTA_START	DD	?
DELTA_ENTRY	DB	?
		DB	?
		DB	?
		DB	?

START_BLOCK	DD	?
ENTRY		DD	?
NUM_DIR_BLOCKS		DD	?
WONT			DD	?
DIRECTORY_BLOCKS	DD	MAX_DIRECTORIES/(PAGE_SIZE/512) DUP(?)

OPEN_SPACE		DB	MAX_DIRECTORIES DUP(?)

endif

		END

